package coder.taiji.test.springnetty.tcp.service;

import coder.taiji.springnetty.server.tcp.state.DeviceStateContext;
import coder.taiji.springnetty.utils.ChannelAttribute;
import coder.taiji.test.springnetty.tcp.dto.TestProtocolDTO;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleStateEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;

/**
 * 设备状态维护的 handler
 *
 * @author helloworldyu
 */
public class DeviceStateHandler extends ChannelInboundHandlerAdapter {
	public static final String LOGIN_INFO = "hello";
	/**
	 * 维护在线设备的 CHANNEL_SESSION
	 */
	public static final ChannelAttribute<DeviceStateContext> CHANNEL_SESSION = new ChannelAttribute<>("state");
	//	ThreadPoolExecutor threadPool = (ThreadPoolExecutor) AppContext.getBean("threadPool");

	private static final Logger LOGGER = LoggerFactory.getLogger(DeviceStateHandler.class);
	@Value("${httpServer.ip}")
	private String httpServer;
	@Value("${httpServer.port}")
	private Integer httpPort;

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) {
		TestProtocolDTO bodyData = (TestProtocolDTO) msg;
		//处理消息
		DeviceStateContext deviceStateContext = CHANNEL_SESSION.getAttributeValue(ctx);

		if (0 == bodyData.getType()) {
			//登录数据,登录成功或者失败的行为在 threadPool 中异步进行
			if (LOGIN_INFO.equals(bodyData.getInfo())) {
				CHANNEL_SESSION.getAttributeValue(ctx).onLoginSucc("123", System.currentTimeMillis(), 10, "登录成功");
			} else {
				CHANNEL_SESSION.getAttributeValue(ctx).onLoginFailed("不是 hello");
			}
		} else {
			//上行数据
			deviceStateContext.onHeartbeat(System.currentTimeMillis(), "设备上行了数据");
			//除登录外的其他数据到业务hander处理
			ctx.fireChannelRead(msg);
		}

		LOGGER.info("channelRead:{}" + deviceStateContext.toString());
	}


	/**
	 * 空闲一段时间，就进行检查 (当前时间-上次上行数据的时间) 如果大于设定的超时时间 设备状态就就行一次 onTimeout
	 *
	 * @param ctx channle 上下文
	 * @param evt 事件
	 * @throws Exception 异常
	 */
	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		if (evt instanceof IdleStateEvent) {
			DeviceStateContext deviceStateContext = CHANNEL_SESSION.getAttributeValue(ctx);
			long lastUpdateTime = deviceStateContext.getLastUpdateTime();
			long currentTimeMillis = System.currentTimeMillis();

			long intervalTime = currentTimeMillis - lastUpdateTime;
			if (intervalTime > deviceStateContext.getHeartRate()) {
				//==============发生超时，进入超时状态==============
				deviceStateContext.onTimeout("设备发生了超时");
				LOGGER.info("发生了超时:{}", deviceStateContext.toString());
			}
		} else {
			//没有超时事件，进行传递
			super.userEventTriggered(ctx, evt);
		}
	}

	/**
	 * 客户端链接上来的时候触发
	 *
	 * @param ctx channle 上下文
	 */
	@Override
	public void channelActive(ChannelHandlerContext ctx) {
		//链接成功
		DeviceStateContext deviceStateContext = new DeviceStateContext(ctx.channel(), true);
		//===========设置设备状态为 未登录=================
		deviceStateContext.onConnect(System.currentTimeMillis(), "设备 active");
		//===========更新添加 state 属性==================
		CHANNEL_SESSION.setAttribute(ctx, deviceStateContext);
		LOGGER.info("新设备链接:{}", deviceStateContext.toString());
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) {
		//================设置为断开================
		DeviceStateContext deviceStateContext = CHANNEL_SESSION.getAttributeValue(ctx);
		deviceStateContext.onDisconnect("设备 inactive");
		LOGGER.info("设备断开链接:{}", deviceStateContext.toString());
	}

	/**
	 * 异常的时候触发
	 *
	 * @param ctx   channle
	 * @param cause 抛出的异常
	 * @throws Exception 发送异常
	 */
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		//==============发生异常切换到断开模式===============
		DeviceStateContext deviceStateContext = CHANNEL_SESSION.getAttributeValue(ctx);
		deviceStateContext.onDisconnect("设备 exceptionCaught");
		LOGGER.info("发生了异常:{},{}", cause.toString(), deviceStateContext.toString());

		super.exceptionCaught(ctx, cause);
	}

}
